﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Runtime.Serialization;
using Newtonsoft.Json;

namespace RAP.Framework.Libary.Utils.Collections.Dictionary
{
    /// <summary>
    /// 键的排序为插入时顺序的列表键值对象
    /// </summary>
    [Serializable]
    public class ListDictionary : IDictionary, IDisposable, ISerializable/*, IDeserializationCallback*/
    {
        /// <summary>
        /// 
        /// </summary>
        protected object _lockObj = new object();

        /// <summary>
        /// 
        /// </summary>
        protected IDictionary _innerDictionay = new Hashtable();

        /// <summary>
        /// 
        /// </summary>
        protected IList<object> _keys = new List<object>();

        /// <summary>
        /// 
        /// </summary>
        protected IList<ListDictionaryItem> _values = new List<ListDictionaryItem>();

        /// <summary>
        /// 集合是否变化
        /// </summary>
        protected int _changeFlags = 0;

        public ListDictionary () { }

        public ListDictionary ( SerializationInfo info, StreamingContext context )
        {
            _keys = info.GetValue( "_keys", typeof( IList<object> ) ) as IList<object>;
            _values = info.GetValue( "_values", typeof( IList<ListDictionaryItem> ) ) as IList<ListDictionaryItem>;
        }

        ~ListDictionary ()
        {
            Dispose();
        }

        #region IDictionary
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Add ( object key, object value )
        {
            lock ( _lockObj )
            {
                _innerDictionay.Add( key, _keys.Count );
                _keys.Add( key );
                _values.Add( new ListDictionaryItem( value ) );
            }
            _changeFlags = 3;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Clear ()
        {
            lock ( _lockObj )
            {
                _innerDictionay.Clear();
                _keys.Clear();
                _values.Clear();
            }
            _changeFlags = 3;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        public void Remove ( object key )
        {
            lock ( _lockObj )
            {
                var idx = getKeyIndex( key );
                if ( idx >= 0 )
                {
                    _innerDictionay.Remove( key );
                    _keys[ idx ] = null;
                    _values[ idx ] = null;
                }
            }
            _changeFlags = 3;
        }

        /// <summary>
        /// 获取键的索引
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected virtual int getKeyIndex ( object key )
        {
            var idx = -1;
            if ( _innerDictionay.Contains( key ) )
            {
                idx = Convert.ToInt32( _innerDictionay[ key ] );
            }
            return idx;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Contains ( object key )
        {
            return _innerDictionay.Contains( key );
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsFixedSize
        {
            get { return _innerDictionay.IsFixedSize; }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsReadOnly
        {
            get { return _innerDictionay.IsReadOnly; }
        }

        protected IList _keysCache = null;
        /// <summary>
        /// 获取键集合
        /// </summary>
        /// <returns></returns>
        protected IList getKeys ()
        {
            if ( _keysCache == null || ( _changeFlags & 1 ) == 1 )
            {
                _changeFlags = _changeFlags ^ 1;
                var keys = from o in _keys where o != null select o;
                _keysCache = keys.ToList();

            }
            return _keysCache;
        }

        /// <summary>
        /// 
        /// </summary>
        public ICollection Keys
        {
            get
            {
                return getKeys();
            }
        }

        protected IList _valuesCache = null;
        /// <summary>
        /// 获取值集合
        /// </summary>
        /// <returns></returns>
        protected IList getValues ()
        {
            if ( _valuesCache == null || ( _changeFlags & 2 ) == 2 )
            {
                _changeFlags = _changeFlags ^ 2;
                var values = from o in _values where o != null select o.value;
                _valuesCache = values.ToList();
            }
            return _valuesCache;
        }
        /// <summary>
        /// 
        /// </summary>
        ICollection IDictionary.Values
        {
            get
            {
                return getValues();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public IList Values
        {
            get { return getValues(); }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object this[ object key ]
        {
            get
            {
                var idx = getKeyIndex( key );
                return idx >= 0 ? _values[ idx ]?.value : null;
            }
            set
            {
                var idx = getKeyIndex( key );
                if ( idx >= 0 )
                {
                    _changeFlags = 3;
                    _values[ idx ] = new ListDictionaryItem( value );
                }
                else
                {
                    this.Add( key, value );
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="array"></param>
        /// <param name="index"></param>
        public void CopyTo ( Array array, int index )
        {
            getValues().CopyTo( array, index );
        }

        /// <summary>
        /// 
        /// </summary>
        public int Count
        {
            get { return _innerDictionay.Count; }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsSynchronized
        {
            get { return _innerDictionay.IsSynchronized; }
        }

        /// <summary>
        /// 
        /// </summary>
        public object SyncRoot
        {
            get { return _innerDictionay.SyncRoot; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        IEnumerator IEnumerable.GetEnumerator ()
        {
            return getValues().GetEnumerator();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IDictionaryEnumerator GetEnumerator ()
        {
            return new DictionaryEnumerator( this );
        }
        #endregion

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose ()
        {
            if ( _lockObj == null )
            {
                return;
            }
            _lockObj = null;
            if ( _innerDictionay != null )
            {
                try
                {
                    _innerDictionay.Clear();
                }
                catch { }
                _innerDictionay = null;
            }
            if ( _keys != null )
            {
                try
                {
                    _keys.Clear();
                }
                catch { }
                _keys.Clear();
                _keys = null;
            }
            if ( _values != null )
            {
                foreach ( ListDictionaryItem item in _values )
                {
                    try
                    {
                        item.Dispose();
                    }
                    catch { }
                }
                try
                {
                    _values.Clear();
                }
                catch { }
                _values = null;
            }
        }

        //public void OnDeserialization( object sender )
        //{
        //    for ( int i = 0; i < _keys.Count; i++ )
        //    {
        //        var key = _keys[ i ];
        //        if ( key != null )
        //        {
        //            _innerDictionay[ key ] = _values[ i ].value;
        //        }
        //    }
        //}

        public void GetObjectData ( SerializationInfo info, StreamingContext context )
        {
            info.AddValue( "_keys", this.Keys );
            info.AddValue( "_values", this.Values );
        }

        /// <summary>
        /// 存储值得对象
        /// </summary>
        [Serializable]
        protected class ListDictionaryItem : IDisposable, ISerializable
        {
            public ListDictionaryItem ( object value )
            {
                this.value = value;
            }

            public ListDictionaryItem ( SerializationInfo info, StreamingContext context )
            {
                this.value = info.GetValue( "value", typeof( object ) );
            }

            public object value { get; set; }

            public void Dispose ()
            {
                this.value = null;
            }

            public void GetObjectData ( SerializationInfo info, StreamingContext context )
            {
                info.AddValue( "value", value );
            }
        }

        #region DictionaryEnumerator
        /// <summary>
        /// 
        /// </summary>
        public class DictionaryEnumerator : IDictionaryEnumerator
        {
            /// <summary>
            /// 
            /// </summary>
            protected IList<DictionaryEntry> _items = new List<DictionaryEntry>();

            /// <summary>
            /// 
            /// </summary>
            protected int _currentIndex = -1;

            /// <summary>
            /// 
            /// </summary>
            /// <param name="listDictionary"></param>
            public DictionaryEnumerator ( ListDictionary listDictionary )
            {
                var idx = 0;
                lock ( listDictionary._lockObj )
                {
                    foreach ( object key in listDictionary.Keys )
                    {
                        if ( key != null )
                        {
                            var value = listDictionary._values[ idx ];
                            if ( value != null )
                            {
                                _items.Add( new DictionaryEntry( key, value.value ) );
                            }
                        }
                        idx++;
                    }
                }
            }

            /// <summary>
            /// Return the current item.
            /// </summary>
            public Object Current { get { ValidateIndex(); return _items[ _currentIndex ]; } }

            /// <summary>
            /// Return the current dictionary entry.
            /// </summary>
            public DictionaryEntry Entry
            {
                get { return ( DictionaryEntry )Current; }
            }

            /// <summary>
            /// Return the key of the current item.
            /// </summary>
            public Object Key { get { ValidateIndex(); return _items[ _currentIndex ].Key; } }

            /// <summary>
            /// Return the value of the current item.
            /// </summary>
            public Object Value { get { ValidateIndex(); return _items[ _currentIndex ].Value; } }

            /// <summary>
            /// Advance to the next item.
            /// </summary>
            /// <returns></returns>
            public Boolean MoveNext ()
            {
                if ( _currentIndex < _items.Count - 1 ) { _currentIndex++; return true; }
                return false;
            }

            /// <summary>
            /// Validate the enumeration index and throw an exception if the index is out of range.
            /// </summary>
            private void ValidateIndex ()
            {
                if ( _currentIndex < 0 || _currentIndex >= _items.Count )
                    throw new InvalidOperationException( "Enumerator is before or after the collection." );
            }

            /// <summary>
            /// Reset the index to restart the enumeration.
            /// </summary>
            public void Reset ()
            {
                _currentIndex = -1;
            }
        }
        #endregion DictionaryEnumerator

        public override string ToString ()
        {
            return JsonConvert.SerializeObject( this );
        }
    }

}
